package com.candy.sys.advice;

import com.alibaba.fastjson.JSONObject;
import com.candy.common.entity.BaseEntity;
import com.candy.common.result.R;
import com.candy.sys.entity.Log;
import com.candy.sys.mapper.LogMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.InetSocketAddress;

@ControllerAdvice
public class SysLogAdvice implements ResponseBodyAdvice , RequestBodyAdvice
{
	private ThreadLocal<Object> param = new ThreadLocal<>();

	@Resource
	private LogMapper logMapper;

	@Override
	public boolean supports(MethodParameter methodParameter, Class aClass) {
		//这个地方如果返回false ,不会执行 beforeBodyWrite 方法
		return true;
	}

	@Override
	public Object beforeBodyWrite(Object result, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest request, ServerHttpResponse response)
	{
		Log log = new Log();
		log.setRequestMethod(request.getMethodValue());
		ServletServerHttpRequest req = (ServletServerHttpRequest)request;
		log.setUrl(request.getURI().getPath());
		StringBuilder paramBuf = new StringBuilder();
		if(StringUtils.isNotEmpty(req.getURI().getQuery()))
		{
			paramBuf.append("query:"+req.getURI()
					.getQuery()+";");
		}
		InetSocketAddress remoteAddress = request.getRemoteAddress();
		log.setIp(remoteAddress.getHostString());
		Object paramObject = param.get();
		if(paramObject!=null)
		{
			paramBuf.append("body:"+JSONObject.toJSONString(paramObject));
		}
		log.setParam(paramBuf.toString());
		if(result instanceof R)
		{
			R result1 = (R) result;
			log.setCode((Integer) result1.get("code"));
			Object dataObject = result1.get("data");
			if(dataObject!=null && dataObject instanceof BaseEntity)
			{
				log.setBusinessId(((BaseEntity) dataObject).getId());
			}
		}
		log.setResult(JSONObject.toJSONString(result));
		logMapper.insert(log);
		return result;
	}

	@Override
	public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass)
	{
		return methodParameter.hasParameterAnnotation(RequestBody.class);
	}

	@Override
	public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass)
	{
		return o;
	}

	@Override
	public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException
	{
		return httpInputMessage;
	}

	@Override
	public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass)
	{
		param.set(o);
		return o;
	}
}